import 'dart:math';
import 'package:flutter/material.dart';
import 'package:sliding_motion/ly_app_color.dart';
import 'package:sliding_motion/ly_sliding_controller.dart';

enum LYSlidingDirection {
  horizontal,
  vertical,
}

class LYUnidirectionalSlidingControl extends StatefulWidget {
  final Function(double value)? onVerticalSliding;
  final Function(double value)? onHorizontalSliding;
  final Function(LYSlidingDirection)? onEnd;
  final Function(LYSlidingDirection)? onStart;
  final double boundsSize;
  final double padSize;
  final Widget? leftWidget;
  final Widget? rightWidget;
  final Widget? topWidget;
  final Widget? bottomWidget;
  final Widget? padWidget;
  final double maxValue;
  final double minValue;
  final bool enable;

  const LYUnidirectionalSlidingControl(
      {super.key,
      this.onVerticalSliding,
      this.onHorizontalSliding,
      this.onEnd,
      this.onStart,
      this.boundsSize = 160,
      this.padSize = 55,
      this.bottomWidget,
      this.topWidget,
      this.leftWidget,
      this.rightWidget,
      this.padWidget,
      this.maxValue = 1,
      this.minValue = 0,
      this.enable = true})
      : assert(maxValue > minValue && minValue >= 0, 'minValue必须大于或等于0，maxValue值必须大于minValue');

  @override
  State<LYUnidirectionalSlidingControl> createState() => _LYUnidirectionalSlidingControlState();
}

class _LYUnidirectionalSlidingControlState extends State<LYUnidirectionalSlidingControl> {
  LYSlidingController controller = LYSlidingController();
  late double limit;
  final double _space = 10;
  late double r;
  bool isNeedCalculate = false;
  late double deltaValue;
  late Widget padWidget;

  @override
  void initState() {
    super.initState();
    initWidget();
    r = widget.boundsSize * 0.5;
    limit = (widget.boundsSize - widget.padSize) * 0.5;
    isNeedCalculate = widget.maxValue != 1 || widget.maxValue != 0;
    deltaValue = widget.maxValue - widget.minValue;
  }

  void initWidget() {
    padWidget = widget.padWidget ??
        Container(
          width: widget.padSize,
          height: widget.padSize,
          decoration: BoxDecoration(
              color: AppColor.whiteColor,
              borderRadius: BorderRadius.circular(widget.padSize * 0.5)),
        );
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      width: widget.boundsSize,
      height: widget.boundsSize,
      alignment: Alignment.center,
      decoration: BoxDecoration(
        color: const Color(0x4D787878),
        borderRadius: BorderRadius.circular(r),
      ),
      child: Stack(
        fit: StackFit.expand,
        alignment: Alignment.center,
        children: [
          ListenableBuilder(
            listenable: controller,
            builder: (ctx, child) {
              return Transform.translate(
                offset: controller.position,
                child: child,
              );
            },
            child: GestureDetector(
              onVerticalDragStart: (details) =>
                  _onPanStart(details: details, direction: LYSlidingDirection.vertical),
              onHorizontalDragStart: (details) =>
                  _onPanStart(details: details, direction: LYSlidingDirection.horizontal),
              onHorizontalDragEnd: (details) =>
                  _onPanEnd(details: details, direction: LYSlidingDirection.horizontal),
              onVerticalDragEnd: (details) =>
                  _onPanEnd(details: details, direction: LYSlidingDirection.vertical),
              onVerticalDragUpdate: widget.onVerticalSliding != null ? _onVerticalDragUpdate : null,
              onHorizontalDragUpdate:
                  widget.onHorizontalSliding != null ? _onHorizontalDragUpdate : null,
              child: Center(
                child: padWidget,
              ),
            ),
          ),
          Positioned(
            left: _space,
            child: widget.leftWidget ??
                const Icon(
                  Icons.arrow_back_ios,
                  size: 15,
                  weight: 900,
                ),
          ),
          Positioned(
              right: _space,
              child: widget.rightWidget ??
                  const Icon(
                    Icons.arrow_forward_ios_rounded,
                    size: 15,
                  )),
          Positioned(
            top: _space,
            child: widget.topWidget ?? const Icon(Icons.keyboard_arrow_up_sharp),
          ),
          Positioned(
            bottom: _space,
            child: widget.bottomWidget ?? const Icon(Icons.keyboard_arrow_down_sharp),
          ),
        ],
      ),
    );
  }

  void _onVerticalDragUpdate(DragUpdateDetails detail) {
    double dy = (detail.localPosition - controller.startMoveOffset).dy;
    dy = dy < 0 ? max(dy, -limit) : min(dy, limit);
    controller.position = Offset(0, dy);
    final scale = -dy / limit;
    if (!isNeedCalculate) {
      widget.onVerticalSliding?.call(scale);
      return;
    }
    final ys = scale < 0 ? -1 : 1;
    final y = (deltaValue * scale.abs() + widget.minValue) * ys;
    widget.onVerticalSliding?.call(y);
  }

  void _onHorizontalDragUpdate(DragUpdateDetails detail) {
    double dx = (detail.localPosition - controller.startMoveOffset).dx;
    dx = dx < 0 ? max(dx, -limit) : min(dx, limit);
    controller.position = Offset(dx, 0);
    final scale = dx / limit;
    if (!isNeedCalculate) {
      widget.onHorizontalSliding?.call(dx / limit);
      return;
    }
    final xs = scale < 0 ? -1 : 1;
    final x = (deltaValue * scale.abs() + widget.minValue) * xs;
    widget.onHorizontalSliding?.call(x);
  }

  void _onPanStart({required DragStartDetails details, required LYSlidingDirection direction}) {
    controller.startMoveOffset = details.localPosition;
    widget.onStart?.call(direction);
  }

  void _onPanEnd({required DragEndDetails details, required LYSlidingDirection direction}) {
    controller.position = Offset.zero;
    widget.onEnd?.call(direction);
  }
}
